use crate::math::{Matrix4f, Vector3f};




#[derive(Debug, Clone, Copy, PartialEq, Eq,serde::Serialize, serde::Deserialize)]
pub enum CameraType {
    Orthographic,
    Perspective,
}



pub trait Camera {
    fn new_with_orthographic(left:f32,right:f32,bottom:f32,top:f32) -> Self;
    fn new_with_perspective(fovy:f32,aspect:f32, znear:f32,zfar:f32) -> Self;
    fn update_view(&mut self);
    fn get_view_projection(&self) -> Matrix4f;
    fn get_camera_type(&self) -> CameraType;
    fn get_view(&self) -> Matrix4f;
    fn get_projection(&self) -> Matrix4f;
}




pub struct SceneCamera {
    view:               Matrix4f,
    projection:         Matrix4f,
    view_projection:    Matrix4f,
    pub camera_type:    CameraType,
}


impl Camera for SceneCamera {
    fn new_with_orthographic(left:f32,right:f32,bottom:f32,top:f32) -> Self {
        let projection = Matrix4f::orthographic(left,right,bottom,top, -1.0, 1.0);
   
        let view = Matrix4f::identity();
        let view_projection = Matrix4f::identity();
        let mut camera = Self {
            view,
            projection,
            view_projection,
            camera_type:        CameraType::Orthographic,
        };
        camera.update_view();
        camera
    }

    fn new_with_perspective(fovy:f32, aspect:f32,znear:f32,zfar:f32) -> Self {
     
        let projection = Matrix4f::perspective(fovy, aspect,  znear, zfar);
    
        let view = Matrix4f::identity();
        let view_projection = Matrix4f::identity();
        let mut camera = Self {
            view,
            projection,
            view_projection,
            camera_type: CameraType::Perspective
        };
        camera.update_view();
        camera
    }



    fn update_view(&mut self) {
        self.view_projection = self.projection * self.view;
    }

    fn get_view_projection(&self) -> Matrix4f {
        self.view_projection
    }

    fn get_camera_type(&self) -> CameraType {
        self.camera_type
    }

    fn get_view(&self) -> Matrix4f {
        self.view
    }

    fn get_projection(&self) -> Matrix4f {
        self.projection
    }
}

impl SceneCamera {
    pub fn set_view(&mut self , view:Matrix4f) {
        self.view = view;
    }

    pub fn set_projection(&mut self , projection:Matrix4f) {
        self.projection = projection;
    }
}

